home *** CD-ROM | disk | FTP | other *** search
- /*
- © Copyright 1990 Apple Computer, Inc. All Rights Reserved.
-
- Programmed by Ricardo Batista, 07/06/90
-
-
- This is a test application.
- The idea is to be able to load and execute an application from a 4D external or
- HyperCard XCMD. The reason is that we need to be able to use the library code
- from TMS, which uses global code and requires a jump table.
- TMS harcoded in assembly language references trough a5, therefore requiring a
- jump table, if the code had been compiled with C or Pascal, the code could have
- been recompiled to use PC relative references, making the tms library compatible
- with code resources such as externals for 4D and HyperCard.
-
- Our workaround consists of creating an application inside an application.
- Sounds scary huh ?
- All we need to do is make a pointer big enough to hold an application, initialize
- a new heap zone, setup a stack, an a5 world, load the application and save some
- low memory global variables.
-
- To communicate with the application we will pass a parameter block pointer at the
- base of the stack, making it easy to access for the application.
-
- Notice that the application must not call GetNextEvent or WaitNextEvent, the
- reason is that MultiFinder will reset the stack and the current heap to the original
- heap and stack of the parent application. What does this mean ? It means that as
- soon as the call to GetNextEvent returns, the application will be using the wrong stack
- and heap. (read it as in trash memory, would ya ?)
-
- In fact, the application we call should not try to make dialog boxes or anything like
- that, we just want the application to compress and decompress images, ok ?
-
- Also, the application should not call ExitToShell, just quit by ending the main loop.
-
- The code in this file could be modified to patch ExitToShell (for quitting) and
- GetNextEvent-WaitNextEvent so we could save and restore the real stack and heap, but
- hey, I don't have the need or the time.
-
- This is a map of how memory looks:
-
-
- ------------------------- Main Application heap zone END ( $400 as an example)
- | |
- | A5, jump table, etc.. |
- | |
- ------------------------- Sub Application space END ($300 as an example)
- | Above a5 |
- ----------------- <-- a5
- | Jump Table |
- -----------------
- | Below a5 |
- ----------------- <-- Stack Base
- | Stack |
- ----------------- <-- Stack END, Application limit
- | Memory avail. |
- | for heap |
- ----------------- <-- Initial Heap END
- | Zone Trailer |
- -----------------
- | Heap Zone |
- -----------------
- | Zone Header |
- ------------------------- <-- Sub Application Heap Zone Begin, space Begin, ($200 as an example)
- | |
- | Main App Heap Zone |
- | |
- ------------------------- <-- Main application Heap Zone Begin, ($100 as an example)
-
-
- The idea is that once the new world has been created for the tms processing application it
- will be kept around until it is no longer needed, we could patch GetNextEvent and take that
- as a signal that the process is done, resuming the call to GetNextEvent when we need to call
- the tms functions again.
- */
-
-
- #include "Types.h"
- #include "Memory.h"
- #include "OSUtils.h"
- #include "Resources.h"
- #include "Files.h"
- #include "SysEqu.h"
-
- #include "Packages.h"
- #include "Dialogs.h"
- #include "Fonts.h"
- #include "Menus.h"
-
-
-
- typedef struct {
- unsigned long aboveA5;
- unsigned long belowA5;
- unsigned long JTSize;
- unsigned long JTOffset;
- unsigned long jumpTable[10];
- } *code0Ptr;
-
-
-
-
-
- typedef struct {
- Handle oldTopMapHandle;
- Handle newTopMapHandle;
- long oldA5;
- long newA5;
- long oldJTOffset;
- long newJTOffset;
- Handle oldCodeHandle;
- Handle newCodeHandle;
- short oldApRefNum;
- short newApRefNum;
- short oldVol;
- short newVol;
- long oldHiHeapMark;
- long newHiHeapMark;
- long oldHeapEnd;
- long newHeapEnd;
- long oldStackBase;
- long newStackBase;
- Ptr oldApplLimit;
- Ptr newApplLimit;
-
- Ptr newZone;
- THz oldZone;
- } Inside, *InsidePtr;
-
-
-
-
-
- long GetApplication(short *oldVol, short *file);
- void GetOldInfo(InsidePtr info);
- void SetInfo(InsidePtr info, Boolean new);
-
-
-
- // A test for a growZone procedure, I don't really want to do anything here
-
- pascal long myProc(long needed)
- {
- DebugStr("\pGrowProc");
- return(needed);
- }
-
-
-
-
- // Main test program, set up the new world and switch worlds
-
- void main(void) {
- InsidePtr info;
- unsigned long memNeeded;
- Handle code;
- code0Ptr code0;
- unsigned long endOfStack;
-
- // for this test only
- MaxApplZone();
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- TEInit();
- InitDialogs(0L);
- InitMenus();
- DrawMenuBar();
- // end this test only
- // if not previously loaded
- info = (InsidePtr) NewPtr(sizeof(Inside));
- GetOldInfo(info);
- memNeeded = GetApplication(&(info->oldVol), &(info->newApRefNum));
- if (!memNeeded) {
- *((Handle*) TopMapHndl) = info->oldTopMapHandle;
- return;
- }
- info->newZone = NewPtr(memNeeded);
- if (!info->newZone) {
- CloseResFile(info->newApRefNum);
- *((Handle*) TopMapHndl) = info->oldTopMapHandle;
- SetVol(0L, info->oldVol);
- return;
- }
- InitZone(myProc, 64, (Ptr) ((long) info->newZone + 8192L), info->newZone); // TheZone changed
- SetResLoad(true);
- code = Get1Resource('CODE', 0);
- if (!code) {
- SetZone(info->oldZone);
- DisposPtr(info->newZone);
- CloseResFile(info->newApRefNum);
- *((Handle*) TopMapHndl) = info->oldTopMapHandle;
- SetVol(0L, info->oldVol);
- return;
- }
- HLock(code);
- code0 = (code0Ptr) *code;
- info->newA5 = (long) info->newZone + memNeeded - code0->aboveA5;
- if (info->newA5 % 4)
- info->newA5 -= 2; // make it long word aligned
- info->newJTOffset = code0->JTOffset;
- info->newStackBase = info->newA5 - code0->belowA5;
- endOfStack = info->newStackBase - 16248L;
- info->newApplLimit = (Ptr) endOfStack;
- // SetApplLimit((Ptr) endOfStack);
- BlockMove((Ptr) &(code0->jumpTable[0]), (Ptr) (info->newA5 + code0->JTOffset),
- code0->JTSize);
- info->newCodeHandle = code;
- info->newTopMapHandle = *((Handle*) TopMapHndl);
- *((char*) WWExist) = false;
- *((char*) QDExist) = false;
- info->newHiHeapMark = ((THz) TheZone)->bkLim;
- info->newHeapEnd = ((THz) TheZone)->bkLim;
- InitAllPacks();
- // end if not previously loaded
-
- info->oldHiHeapMark = *((long*) HiHeapMark);
- info->oldHeapEnd = *((long*) HeapEnd);
- SetInfo(info, true); // true for new info
-
- GOTOAPP();
-
- info->newHiHeapMark = *((long*) HiHeapMark);
- info->newHeapEnd = *((long*) HeapEnd);
- SetInfo(info, false); // restore old info
- *((char*) WWExist) = true;
- *((char*) QDExist) = true;
- // if this was for the last time...
- *((Handle*) TopMapHndl) = info->newTopMapHandle;
- CloseResFile(info->newApRefNum);
- *((Handle*) TopMapHndl) = info->oldTopMapHandle;
- DisposPtr(info->newZone);
- DisposPtr((Ptr) info);
- // end if for the last time
- }
-
-
-
-
-
-
- //
- // Get the global information for the current process
- //
-
- void GetOldInfo(InsidePtr info)
- {
- info->oldTopMapHandle = *((Handle*) TopMapHndl);
- info->oldA5 = *((long*) CurrentA5);
- info->oldJTOffset = *((short*) CurJTOffset);
- info->oldCodeHandle = *((Handle*) SaveSegHandle);
- info->oldApRefNum = *((short*) CurApRefNum);
- info->oldZone = GetZone();
- info->oldStackBase = *((long*) CurStackBase);
- info->oldApplLimit = *((Ptr*) ApplLimit);
- }
-
-
-
-
- //
- // Set the global information for either the original or the enclosed
- // application. This enables the applications to run independently,
- // without corrupting the other one.
-
- void SetInfo(InsidePtr info, Boolean new)
- {
- if (new) {
- *((Handle*) TopMapHndl) = info->newTopMapHandle;
- *((long*) CurrentA5) = info->newA5;
- *((short*) CurJTOffset) = info->newJTOffset;
- *((Handle*) SaveSegHandle) = info->newCodeHandle;
- *((short*) CurApRefNum) = info->newApRefNum;
- *((long*) CurStackBase) = info->newStackBase;
- SetZone((THz) info->newZone);
- *((long*) HiHeapMark) = info->newHiHeapMark;
- *((long*) HeapEnd) = info->newHeapEnd;
- *((Ptr*) ApplZone) = info->newZone;
- *((Ptr*) ApplLimit) = info->newApplLimit;
- }
- else {
- *((Handle*) TopMapHndl) = info->oldTopMapHandle;
- *((long*) CurrentA5) = info->oldA5;
- *((short*) CurJTOffset) = info->oldJTOffset;
- *((Handle*) SaveSegHandle) = info->oldCodeHandle;
- *((short*) CurApRefNum) = info->oldApRefNum;
- *((long*) CurStackBase) = info->oldStackBase;
- SetZone(info->oldZone);
- *((long*) HiHeapMark) = info->oldHiHeapMark;
- *((long*) HeapEnd) = info->oldHeapEnd;
- *((Ptr*) ApplZone) = (Ptr) info->oldZone;
- *((Ptr*) ApplLimit) = info->oldApplLimit;
- }
- }
-
-
-
-
-
-
- //
- // Select an application to load
- // check on its size resource and make sure we have enough memory
- // to load that application, also set the volume and resource file
- //
-
- long GetApplication(short *oldVol, short *file)
- {
- long prefSize = 524288L, minSize = 524288L;
- long mem;
- SFReply reply;
- SFTypeList fTypes;
- Point where;
- register short err;
- Handle H;
-
- fTypes[0] = 'APPL';
- where.h = where.v = 100;
- SFGetFile(where, "\p", 0L, 1, fTypes, 0L, &reply);
- if (!reply.good)
- return (0L);
- err = GetVol(0L, oldVol);
- err = SetVol(0L, reply.vRefNum);
- // *((Handle*) TopMapHndl) = 0L;
- *file = OpenResFile(reply.fName);
- if (*file == -1) {
- DebugStr("\pOpenFile");
- SysBeep(1);
- SetVol(0L, *oldVol);
- return (0L);
- }
- H = Get1Resource('SIZE', -1);
- if (H) {
- LoadResource(H);
- HLock(H);
- BlockMove(*H + (Ptr) 2L, (Ptr) &prefSize, 4L);
- BlockMove(*H + (Ptr) 6L, (Ptr) &minSize, 4L);
- HUnlock(H);
- ReleaseResource(H);
- }
- mem = MaxBlock();
- if (mem > prefSize)
- mem = prefSize;
- else {
- if (mem > minSize)
- mem = minSize;
- else
- mem = 0L;
- }
- if (!mem) {
- DebugStr("\pMemory");
- SysBeep(1);
- CloseResFile(*file);
- SetVol(0L, *oldVol);
- }
- return(mem);
- }
-
-
-
-
-
-
-
-
-
-